package cn.zn.role.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.zn.base.common.utils.AdminUtil;
import cn.zn.base.exception.CustomException;
import cn.zn.role.entity.SysRole;
import cn.zn.role.entity.SysRoleDept;
import cn.zn.role.entity.SysRoleMenu;
import cn.zn.user.entity.SysUserRole;
import cn.zn.role.mapper.SysRoleDeptMapper;
import cn.zn.role.mapper.SysRoleMapper;
import cn.zn.role.mapper.SysRoleMenuMapper;
import cn.zn.user.mapper.SysUserRoleMapper;
import cn.zn.role.service.SysRoleService;
import cn.zn.role.vo.SysRoleEditVo;
import cn.zn.role.vo.SysRolePageVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * <p>
 * 角色信息表 服务实现类
 * </p>
 *
 * @author zn-admin
 * @since 2021-01-28
 */
@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {

    @Autowired
    private SysRoleMenuMapper roleMenuMapper;

    @Autowired
    private SysRoleDeptMapper roleDeptMapper;

    @Autowired
    private SysUserRoleMapper userRoleMapper;

    @Override
    public Object selectRoleList(SysRolePageVo vo) {
        if (!vo.getPage()) {
            return baseMapper.selectRoleList(vo);
        }

        Page<SysRole> page = new Page<>(vo.getCurrent(), vo.getSize());
        return baseMapper.selectRoleList(page, vo);
    }

    @Override
    public Set<String> selectRolePermissionByUserId(String userId, String loginName) {
        Set<String> roles = new HashSet<>();
        if (AdminUtil.isAdmin(loginName)) {
            roles.add(AdminUtil.ADMIN_ROLE);
        } else {
            List<SysRole> perms = baseMapper.selectRolePermissionByUserId(userId);
            for (SysRole perm : perms) {
                if (ObjectUtil.isNotNull(perm)) {
                    roles.addAll(Arrays.asList(perm.getRoleKey().trim().split(",")));
                }
            }
        }
        return roles;
    }

    @Override
    public List<SysRole> selectRolesByUserId(String userId) {
        return baseMapper.selectRolePermissionByUserId(userId);
    }

    @Override
    @Transactional
    public void insertRole(SysRoleEditVo vo) {
        if (!checkRoleNameUnique(vo.getRoleName(), null)) {
            throw new CustomException("新增角色'" + vo.getRoleName() + "'失败，角色名称已存在");
        }

        if (!checkRoleKeyUnique(vo.getRoleKey(), null)) {
            throw new CustomException("新增角色'" + vo.getRoleName() + "'失败，角色权限已存在");
        }

        SysRole role = new SysRole();
        BeanUtil.copyProperties(vo, role);
        role.insert();

        List<SysRoleMenu> list = insertRoleMenu(role.getId(), vo.getMenuIds());
        if (CollUtil.isNotEmpty(list)) {
            for (SysRoleMenu roleMenu : list) {
                roleMenu.insert();
            }
        }
    }

    @Override
    @Transactional
    public void updateRole(String id, SysRoleEditVo vo) {
        SysRole oldRole = baseMapper.selectById(id);
        if (ObjectUtil.isNotEmpty(oldRole) && AdminUtil.isROleAdmin(oldRole.getRoleKey())) {
            throw new CustomException("不允许操作超级管理员角色");
        }

        if (!checkRoleNameUnique(vo.getRoleName(), id)) {
            throw new CustomException("新增角色'" + vo.getRoleName() + "'失败，角色名称已存在");
        }

        if (!checkRoleKeyUnique(vo.getRoleKey(), id)) {
            throw new CustomException("新增角色'" + vo.getRoleName() + "'失败，角色权限已存在");
        }

        SysRole role = new SysRole();
        BeanUtil.copyProperties(vo, role);
        role.setId(id);
        role.updateById();

        QueryWrapper<SysRoleMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("role_id", id);
        roleMenuMapper.delete(queryWrapper);

        List<SysRoleMenu> list = insertRoleMenu(role.getId(), vo.getMenuIds());
        if (CollUtil.isNotEmpty(list)) {
            for (SysRoleMenu roleMenu : list) {
                roleMenu.insert();
            }
        }
    }

    @Override
    @Transactional
    public void updateRoleStatus(String id, SysRoleEditVo vo) {
        SysRole oldRole = baseMapper.selectById(id);
        if (ObjectUtil.isNotEmpty(oldRole) && AdminUtil.isROleAdmin(oldRole.getRoleKey())) {
            throw new CustomException("不允许操作超级管理员角色");
        }

        baseMapper.updateStatus(vo.getStatus(), id);
    }

    @Override
    @Transactional
    public void deleteRoleByIds(String[] roleIds) {
        for (String roleId : roleIds) {
            SysRole role = baseMapper.selectById(roleId);
            if (ObjectUtil.isNotEmpty(role) && AdminUtil.isROleAdmin(role.getRoleKey())) {
                throw new CustomException("不允许操作超级管理员角色");
            }

            QueryWrapper<SysUserRole> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("role_id", roleId);
            int count = userRoleMapper.selectCount(queryWrapper);
            if (count > 0) {
                throw new CustomException(String.format("%1$s已分配,不能删除", role.getRoleName()));
            }
        }
        // 删除角色与菜单关联
        roleMenuMapper.deleteRoleMenu(roleIds);
        // 删除角色与部门关联
        roleDeptMapper.deleteRoleDept(roleIds);
        baseMapper.deleteBatchIds(Arrays.asList(roleIds));
    }

    @Override
    @Transactional
    public void authDataScope(String id, SysRoleEditVo vo) {
        SysRole oldRole = baseMapper.selectById(id);
        if (ObjectUtil.isNotEmpty(oldRole) && AdminUtil.isROleAdmin(oldRole.getRoleKey())) {
            throw new CustomException("不允许操作超级管理员角色");
        }

        baseMapper.updateDataScope(vo.getDataScope(), id);

        /*QueryWrapper<SysRoleDept> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("role_id", id);
        roleDeptMapper.delete(queryWrapper);

        List<SysRoleDept> list = insertRoleDept(id, vo.getDeptIds());
        if (CollUtil.isNotEmpty(list)) {
            for (SysRoleDept roleDept : list) {
                roleDept.insert();
            }
        }*/
    }

    /**
     * 新增角色菜单信息
     *
     * @param menuIds 角色对象
     */
    private List<SysRoleMenu> insertRoleMenu(String id, String[] menuIds) {
        // 新增用户与角色管理
        List<SysRoleMenu> list = new ArrayList<>();
        if (ArrayUtil.isNotEmpty(menuIds)) {
            for (String menuId : menuIds) {
                SysRoleMenu rm = new SysRoleMenu();
                rm.setRoleId(id);
                rm.setMenuId(menuId);
                list.add(rm);
            }
        }
        return list;
    }

    /**
     * 新增角色部门信息(数据权限)
     *
     * @param deptIds 角色对象
     */
    private List<SysRoleDept> insertRoleDept(String id, String[] deptIds) {
        // 新增角色与部门（数据权限）管理
        List<SysRoleDept> list = new ArrayList<>();
        if (ArrayUtil.isNotEmpty(deptIds)) {
            for (String deptId : deptIds) {
                SysRoleDept rd = new SysRoleDept();
                rd.setRoleId(id);
                rd.setDeptId(deptId);
                list.add(rd);
            }
        }
        return list;
    }

    /**
     * 校验角色名称是否唯一
     *
     * @param roleName, 角色信息
     * @return 结果
     */
    private Boolean checkRoleNameUnique(String roleName, String id) {
        QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("role_name", roleName);
        if (StrUtil.isNotBlank(id)) {
            queryWrapper.ne("id", id);
        }
        int count = baseMapper.selectCount(queryWrapper);
        return count == 0;
    }

    /**
     * 校验角色权限是否唯一
     *
     * @param roleKey 角色信息
     * @return 结果
     */
    private Boolean checkRoleKeyUnique(String roleKey, String id) {
        QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("role_key", roleKey);
        if (StrUtil.isNotBlank(id)) {
            queryWrapper.ne("id", id);
        }
        int count = baseMapper.selectCount(queryWrapper);
        return count == 0;
    }

}
